#include <iostream>
#include <sstream>

#include <typeinfo>


#include <cppunit/TestCase.h>
#include <cppunit/TestFixture.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestSuite.h>

#include <cppunit/ui/text/TestRunner.h>

#include "rep/rep.hpp"
#include "rep/running.hpp"
#include "vm/opcodes.hpp"
#include "vm/builtins.hpp"


using namespace std;
using namespace rep;

namespace vm{
  class BuiltinTest : public CppUnit::TestFixture{
  public:

    void setUp(){
      Builtin::initialize();
      ftype = FrameType(NULL, 16, NULL, NULL);
    }
    void tearDown(){}
  protected:
    Block code;
    FrameType ftype;
    Instruction print_instr;
    
    void testDummy(){}

    void testIntAdd(){
      code.code.push_back(BuiltinInstructions::intAdd);
      code.code.push_back(BuiltinInstructions::print);
      Slot three;
      Slot two;
      Cons* st = NULL;
      Slot* env = FrameHelper::alloc(&ftype);
      IntegerHelper::assign(&three, 3);
      IntegerHelper::assign(&two, 2);
      st = st->push(two)->push(three);
      Continuation cont (st, env, &code, 0);
      Continuation next = cont.next();
      CPPUNIT_ASSERT(next.stack);
      CPPUNIT_ASSERT_EQUAL(next.stack->car.i, 5);
      //next.next();
    }

  public:
    static CppUnit::Test* suite(){
      CppUnit::TestSuite *suite = new CppUnit::TestSuite("BuiltinTest");

      suite->addTest( new CppUnit::TestCaller<BuiltinTest>("testIntAdd", 
                                                        &BuiltinTest::testIntAdd));
      return suite;
    }
  };
};
